package MetodosSistEcLineales;

import java.util.Collection;
import java.util.LinkedList;

import Elementos.Componente;
import Elementos.ComponenteMatricial;
import Elementos.FuncionesUtil;
import Elementos.Matriz;
import Elementos.SistemaEcuacionLineal;
import Elementos.Vector;

/**
 * @author EstudioOsio
 *
 */
public class EliminacionGauss {
	
	/***
	 * Eliminacion gaussiana sin pivoteo, 
	 * la matriz tiene que ser cuadrada y de solucion unica
	 * @param unSistemaLineal
	 * @return
	 */
	public static Vector gaussSimple(SistemaEcuacionLineal unSistemaLineal){
		
		Matriz unaMatrizOriginal = unSistemaLineal.getMatriz();
		Matriz unaMatriz = unaMatrizOriginal.clonar();
		Vector unVector = unSistemaLineal.getVector_b().clonar();
		Collection<ComponenteMatricial>  listaM = new LinkedList<ComponenteMatricial>();
		if (unaMatriz == null)
			return null;
		if (unVector == null)
			return null;
		
		//Eliminacion hacia adelante
		System.out.println("Elimnacion Gaussiana");
		System.out.println("====================");
		unaMatriz.imprimirPorConsola();
		unVector.imprimirPorConsola();
		System.out.println("====================");
		//Eliminacion hacia adelante
		Double factor;
		int n =unaMatriz.getCantFilas();
		for(int k = 1; k<n;k++){
			pivoteParcial(unaMatriz,unVector,k);
			for (int i = k+1;i<=n;i++){
				factor = unaMatriz.getValor(i, k)/unaMatriz.getValor(k, k);
				for (int j=k+1;j<=n;j++){
					double arriba = factor*unaMatriz.getValor(k, j);
					double abajo = unaMatriz.getValor(i, j);
					double Aij=abajo-arriba;
					unaMatriz.setValor(i, j, Aij);
					unaMatriz.setValor(i, k, 0.0);
				}
				double bi = unVector.componente(i)-factor*unVector.componente(k);
				unVector.setComponente(i, bi);
				ComponenteMatricial mij =  new ComponenteMatricial(i,k,factor); 
				listaM.add(mij);
			}
			unaMatriz.imprimirPorConsola();
			unVector.imprimirPorConsola();
			System.out.println("====================");
		};	
			
		// Sustitucion hacia atras
		Collection<Componente> unaListaComponentes = new LinkedList<Componente>();
		
		double unValorX = unVector.componente(n)/unaMatriz.getValor(n,n);
		Componente unComponente = new Componente(n,unValorX);
		unaListaComponentes.add(unComponente);
		Vector solucionX = new Vector(unaListaComponentes,unaMatriz.getCantColumnas());
		
		for (int i=n-1;i>=1;i--){
			double sum =0;
			for (int j=i+1;j<=n;j++)
				sum = sum + unaMatriz.getValor(i, j)*solucionX.componente(j);
			unValorX = (unVector.componente(i)-sum)/unaMatriz.getValor(i,i);
			unComponente = new Componente(i,unValorX);
			
			solucionX.setComponente(i, unValorX);
		}
		
		return solucionX;
	
	}
	

	/**
	 * 
	 * @param unaMatriz
	 * @param unVector
	 * @param k
	 */
	private static void pivoteParcial(Matriz unaMatriz, Vector unVector, int k) {
		int p=k;
		int n=unaMatriz.getCantFilas();
		double big = Math.abs(unaMatriz.getValor(k,k));
		double dummy =0;
		for (int i=k+1;i<=n;i++){
			dummy=Math.abs(unaMatriz.getValor(i, k));
			if (dummy>big){
				big=dummy;
				p=i;
			}
		}
		if (p!=k){
			for (int j=k;j<=n;j++){
				dummy=unaMatriz.getValor(p, j);
				unaMatriz.setValor(p, j,unaMatriz.getValor(k, j));
				unaMatriz.setValor(k, j, dummy);
			}
			dummy=unVector.componente(p);
			unVector.setComponente(p, unVector.componente(k));
			unVector.setComponente(k, dummy);
			System.out.println("========Pivoteo=====");
			unaMatriz.imprimirPorConsola();
			unVector.imprimirPorConsola();
			System.out.println("====================");
		}
	}


	/**
	 * Eliminacion por gauss con truncamiento
	 * la matriz tiene que ser cuadrada y de solucion unica
	 * @param unSistemaLineal
	 * @param nDec
	 * @return
	 */
	public static Vector gaussSimpleTruncado(SistemaEcuacionLineal unSistemaLineal, int nDec){
		
		Matriz unaMatrizOriginal = unSistemaLineal.getMatriz();
		Matriz unaMatriz = unaMatrizOriginal.clonar();
		Vector unVector = unSistemaLineal.getVector_b().clonar();
		Collection<ComponenteMatricial>  listaM = new LinkedList<ComponenteMatricial>();
		if (unaMatriz == null)
			return null;
		if (unVector == null)
			return null;
		
		//Eliminacion hacia adelante
		System.out.println("Elimnacion Gaussiana");
		System.out.println("====================");
		unaMatriz.imprimirPorConsola();
		unVector.imprimirPorConsola();
		System.out.println("====================");
		Double factor;
		int n =unaMatriz.getCantFilas();
		for(int k = 1; k<n;k++){
			pivoteParcial(unaMatriz,unVector,k);
			for (int i = k+1;i<=n;i++){
				factor = FuncionesUtil.Truncar(unaMatriz.getValor(i, k)/unaMatriz.getValor(k, k),nDec);
				for (int j=k+1;j<=n;j++){
					double arriba = FuncionesUtil.Truncar(factor*unaMatriz.getValor(k, j),nDec);
					double abajo = unaMatriz.getValor(i, j);
					double Aij=FuncionesUtil.Truncar(abajo-arriba,nDec);
					unaMatriz.setValor(i, j, Aij);
					unaMatriz.setValor(i, k, 0.0);
				}
				double bi = FuncionesUtil.Truncar(unVector.componente(i)-factor*unVector.componente(k),nDec);
				unVector.setComponente(i, bi);
				ComponenteMatricial mij =  new ComponenteMatricial(i,k,factor); 
				listaM.add(mij);
			}
			unaMatriz.imprimirPorConsola();
			unVector.imprimirPorConsola();
			System.out.println("====================");
		};	
			
			
		// Sustitucion hacia atras
		Collection<Componente> unaListaComponentes = new LinkedList<Componente>();
		
		double unValorX = FuncionesUtil.Truncar(unVector.componente(n)/unaMatriz.getValor(n,n),nDec);
		Componente unComponente = new Componente(n,unValorX);
		unaListaComponentes.add(unComponente);
		Vector solucionX = new Vector(unaListaComponentes,unaMatriz.getCantColumnas());
		
		for (int i=n-1;i>=1;i--){
			double sum =0;
			for (int j=i+1;j<=n;j++)
				sum = sum + FuncionesUtil.Truncar(unaMatriz.getValor(i, j)*solucionX.componente(j),nDec);
			unValorX = FuncionesUtil.Truncar((unVector.componente(i)-sum)/unaMatriz.getValor(i,i),nDec);
			unComponente = new Componente(i,unValorX);
			
			solucionX.setComponente(i, unValorX);
		}
		
		unaMatrizOriginal.setMultiplicadores(listaM);
		return solucionX;
	
	}
	
}
